package br.com.pentagrama.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;

import br.com.pentagrama.dto.NomeParametro;
import br.com.pentagrama.dto.Parametros;
import br.com.pentagrama.dto.ResultadoPing;
import br.com.pentagrama.exception.PingException;
import br.com.pentagrama.service.IPing;
import br.com.pentagrama.util.ParseUtil;

/**
 * http://razec.wordpress.com/2011/02/04/bug-solucao-inetaddress-isreachable3000
 * -2/
 * 
 * @author Pablo
 * 
 */

public class PingICMP extends PingGenerico implements IPing {

	private Long timeout = 750l;
	
	private Long tamanhoPacote = 64l;

	private static PingICMP instance;
	
	public static PingICMP getInstance() {
		if(instance == null) {
			instance = new PingICMP(0);
		}
		return instance;
	}
	
	private PingICMP(long timeout) {
		this.timeout = timeout;
	}

	public ResultadoPing doPing(String destino, int vezes) {
		ResultadoPing resultado = new ResultadoPing();
		for (int i = 0; i < vezes; i++) {
			try {
				long latenciaPing = ping(destino);
				resultado.resultados.add(latenciaPing);
			} catch (PingException pe) {
				resultado.falha();
				Logger.getLogger(PingICMP.class.getName()).log(Level.INFO, "", pe);
			} catch (IOException e) {
				resultado.falha();
				Logger.getLogger(PingICMP.class.getName()).log(Level.INFO, "", e);
			} catch (InterruptedException e) {
				Logger.getLogger(PingICMP.class.getName()).log(Level.INFO, "", e);
				resultado.falha();
			}
		}
		return resultado;
	}

	public long ping(String target) throws IOException, InterruptedException,
			PingException {
		delay(500);
		String os = System.getProperty("os.name");
		if (os.startsWith("Windows")) {
			// ping windows pode ser definido um timeout
			return pingWin(target);
		} else {
			// o ping unix não possui timeout definido pelo programa
			return pingUnix(target);
		}
	}

	public long pingWin(String target) throws IOException,
			InterruptedException, PingException {
		String[] cmd = {};
		if (timeout == 0) {
			cmd = new String[6];
		} else {
			cmd = new String[8];
			cmd[cmd.length - 2] = "-w";
			cmd[cmd.length - 1] = Long.toString(timeout);
		}
		cmd[0] = "ping";
		cmd[1] = target;
		cmd[2] = "-n";
		cmd[3] = Integer.toString(1); // sempre executa apenas 1 ping
		cmd[4] = "-l";
		cmd[5] = tamanhoPacote.toString();
		return ping(cmd);
	}

	public long pingUnix(String target) throws IOException,
			InterruptedException, PingException {
		// TODO acrescentar tamanho do pacote
		return ping(new String[] { "ping", target, "-c", Integer.toString(1) });
	}

	private long ping(String[] cmd) throws IOException, InterruptedException,
			PingException {
		Process proccess = Runtime.getRuntime().exec(cmd);
		int waitFor = proccess.waitFor();

		if (waitFor != 0) {
			throw new PingException("Host n\u00E3o respondeu ao ping: " + cmd[1]);
		}

		String linha = "";
		StringBuilder stringBuilder = new StringBuilder();
		BufferedReader buf = new BufferedReader(new InputStreamReader(
				proccess.getInputStream()));
		while ((linha = buf.readLine()) != null) {
			stringBuilder.append(linha);
		}

		return ParseUtil.getMiliSegundos(stringBuilder.toString());
	}

	public void delay(int tempo) {
		try {
			Thread.sleep(tempo);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
